package engine.objects;

import engine.graphics.IRender;
import engine.graphics.Vertex2f;
import engine.system.IInit;

import java.io.Serializable;
import java.util.ArrayList;

public class GameObjects implements IInit, IRender, Serializable {

	private static final long serialVersionUID = 1L;

	private ArrayList<PhysicsObject> objects;

	public GameObjects(){
		init();
	}
	
	public void init() {
		objects = new ArrayList<PhysicsObject>();
	}

	public ArrayList<PhysicsObject> getObjects() {
		return objects;
	}

	public void addNewObject(PhysicsObject b) {
		if (!(b == null))
			objects.add(b);
	}

	public void addObjects(ArrayList<PhysicsObject> objects) {
		for (PhysicsObject b1 : objects)
			addNewObject(b1);
	}

	public void addObjects(PhysicsObject[] objects) {
		for (PhysicsObject b1 : objects)
			addNewObject(b1);
	}

	public boolean canCollide(PhysicsObject o){
		return (!(o == null) && o.isCollidable()); 
	}
	
	public void colliding(PhysicsObject b) {
		ObjectCollision result1 = ObjectCollision.getDefaultObjectCollision(); 
		if (this.canCollide(b))
			for (PhysicsObject b1 : objects)
				if (b1 != b){
					if (b.collidingWith(b1)){
						if(b1.isCollidable()){
							result1 = new ObjectCollision(b1, true);
							b1.setObjectCollision(new ObjectCollision(b, true));
						}else{
							result1 = new ObjectCollision(b1, false);
							b1.setObjectCollision(new ObjectCollision(b, false));
						}
					}
					if(result1.isColliding()) break ; 
				}
		b.setObjectCollision(result1); 
	}

	public void colliding(PhysicsObject b, PhysicsObject target) {
		b.setObjectCollision(new ObjectCollision(target, (this.canCollide(b) && this.canCollide(target) && b.collidingWith(target))));
		target.setObjectCollision(new ObjectCollision(b, (this.canCollide(b) && this.canCollide(target) && b.collidingWith(target))));
	}

	public void colliding(PhysicsObject b, Vertex2f velocity) {
		ObjectCollision result = ObjectCollision.getDefaultObjectCollision();
		if (this.canCollide(b)) {
			int vx = (int) velocity.getX();
			int vy = (int) velocity.getY();
			int x = (int) b.getMinX();
			int y = (int) b.getMinY();
			int w = (int) b.getWidth();
			int h = (int) b.getHeight();
			int tmpx = x, tmpy = y, tmpw = w, tmph = h;
			if (vx > 0)
				tmpw += vx;
			else if (vx < 0)
				tmpx -= Math.abs(vx);
			if (vy > 0)
				tmph += vy;
			else if (vy < 0)
				tmpy -= Math.abs(vy);
			PhysicsObject tmp = new PhysicsObject(b.getManager(), tmpx, tmpy, tmpw, tmph, b.isCollidable());
			for (PhysicsObject b1 : objects) {
				if (b1 != b) {
					if (tmp.collidingWith(b1)) {
						if(b1.isCollidable()){
							result = new ObjectCollision(b1, true);
							b1.setObjectCollision(new ObjectCollision(b, true));
						}
						else{
							result = new ObjectCollision(b1, false);
							b1.setObjectCollision(new ObjectCollision(b, false));
						}
					}
				}
				if (result.isColliding()) {
					if (b.collidingWith(b1)) {
						if (vx > 0)
							b.setBounds((int) (b1.getMinX() - w - 1), y, w, h);
						else if (vx < 0)
							b.setBounds((int) (b1.getMaxX() + 1), y, w, h);
						if (vy > 0)
							b.setBounds(x, (int) (b1.getMinY() - h - 1), w, h);
						else if (vy < 0)
							b.setBounds(x, (int) (b1.getMaxY() + 1), w, h);
					}
					break;
				}
			}
		}
		b.setObjectCollision(result); 
	}

	public ObjectCollision colliding(Line l, Vertex2f velocity) {
		ObjectCollision result = ObjectCollision.getDefaultObjectCollision();
		if (!(l == null)) {
			// int vx = velocity.getX();
			// int vy = velocity.getY();
			int x1 = (int) l.getX1();
			int x2 = (int) l.getX2();
			int y1 = (int) l.getY1();
			int y2 = (int) l.getY2();
			for (PhysicsObject b1 : objects) {
				if (b1.intersectsLine(x1, y1, x2, y2))
					result = new ObjectCollision(b1, true);
				if (result.isColliding())
					break;
			}
		}
		return result;
	}

	public ObjectCollision collidingExcept(Line l, BoundingBox except,
			Vertex2f velocity) {
		ObjectCollision result = ObjectCollision.getDefaultObjectCollision();
		if (!(l == null)) {
			int vx = (int) velocity.getX();
			int vy = (int) velocity.getY();
			int x1 = (int) l.getX1();
			int x2 = (int) l.getX2();
			int y1 = (int) l.getY1();
			int y2 = (int) l.getY2();
			int newx = x2 + vx;
			int newy = y2 + vy;
			for (PhysicsObject b1 : objects) {
				if (b1 != except) {
					if (b1.intersectsLine(x1, y1, newx, newy))
						result = new ObjectCollision(b1, true);
				}
				if (result.isColliding()) {
					break;
				}
			}
		}
		return result;
	}

	@Override
	public void update() {
		for (PhysicsObject o : objects)
			o.update();
	}

	@Override
	public void render() {
		for (PhysicsObject o : objects)
			o.render();
	}

}
